/*
<license>
Copyright (c) 2008, Chris Venter <chris.venter@gmail.com>
All rights reserved.

This file is part of quicktag <http://code.google.com/p/quicktag/>

quicktag is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

quicktag is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this code.
If not, see <http://www.gnu.org/licenses/>.
</license>
*/
#include "ogg_tag.h"

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

// replace with libb64
//#include "base64.h"

#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>

#include "vcedit.h"

#include <iostream>

#define MULTIFIELD_SEPARATOR " - "

#define NUMBER_TRACK_FORMATED 0
#define NUMBER_TRACK_FORMATED_SPIN_BUTTON 0

//gchar* ogg_error_msg;

#define VORBIS_ID(NAME) (char*)#NAME

namespace quicktag
{
	void skip_id3v2(FILE* file)
	{
		// Check for and skip any id3v2 tag
		// This code block remains exactly as it is from the easytag source file ogg_tag.c
		{
			// Skip the id3v2 tag
			guchar tmp_id3[4];
			gulong id3v2size;

			// Check if there is an ID3v2 tag...
			fseek(file, 0L, SEEK_SET);
			if (fread(tmp_id3, 1, 4, file) == 4)
			{
				// Calculate ID3v2 length
				if (tmp_id3[0] == 'I' && tmp_id3[1] == 'D' && tmp_id3[2] == '3' && tmp_id3[3] < 0xFF)
				{
					// id3v2 tag skipeer $49 44 33 yy yy xx zz zz zz zz [zz size]
					fseek(file, 2, SEEK_CUR); // Size is 6-9 position
					if (fread(tmp_id3, 1, 4, file) == 4)
					{
						id3v2size = 10 + ( (long)(tmp_id3[3])   | ((long)(tmp_id3[2]) << 7)
											| ((long)(tmp_id3[1]) << 14) | ((long)(tmp_id3[0]) << 21) );
						fseek(file, id3v2size, SEEK_SET);
						//Log_Print(LOG_ERROR,_("Warning : The Ogg Vorbis file '%s' contains an ID3v2 tag."),filename_utf8);
						//std::cerr<<"Warning : The Ogg Vorbis file '"<<filename<<"' contains an ID3v2 tag."<<std::endl;
					}
					else
					{
						fseek(file, 0L, SEEK_SET);
					}
				}
				else
				{
					fseek(file, 0L, SEEK_SET);
				}
			}
			else
			{
				fseek(file, 0L, SEEK_SET);
			}
		}
	}

	std::string get_string(vorbis_comment* vc, const std::string& field)
	{
		std::string output;
		char* string = vorbis_comment_query(vc, (char*)field.c_str(), 0);
		if (string)
		{
			output = string;
		}
		return output;
	}
	
	std::string get_multistring(vorbis_comment* vc, const std::string& field)
	{
		std::string output;
		int field_num = 0;
		char* string;
		while ( (string = vorbis_comment_query(vc, (char*)field.c_str(), field_num++)) != NULL )
		{
			//std::cerr<<"TITLE: "<<string;
			string = Try_To_Validate_Utf8_String(string);

			if ( g_utf8_strlen(string, -1) > 0 )
			{
				if (output.empty())
				{
					output = string;
				}
				else
				{
					output += MULTIFIELD_SEPARATOR;
					output += string;
				}
				// If strlen = 0, then no allocated data!
			}
			//std::cerr<<" FileTag->title: "<<FileTag->title<<std::endl;

			free(string);
		}
		return output;
	}

	int read_ogg(const std::string& filename, quicktag::tags& tags)
	{
	
		FILE* file = fopen(filename.c_str(), "rb");

		if (!file)
		{
			tags.seterror("could not read file [" + filename + "]");
			return READVAL_FILE;
		}
		
		// check and skip id3v2 tags
		skip_id3v2(file);

		vcedit_state* state = vcedit_new_state();    // Allocate memory for 'state'
		if ( vcedit_open(state,file) < 0 )
		{
			std::string message;
			message = "failed to open file: ";
			message += vcedit_error(state);
			tags.seterror(message);
			//
			fclose(file);
			vcedit_clear(state);
			return READVAL_FILE;
		}
		
		// Get data from tag
		vorbis_comment* vc = vcedit_comments(state);
		
		// Title
		/* Note : don't forget to add any new field to 'Save unsupported fields' */
		tags.title = get_multistring(vc, "TITLE");

		// Artist
		tags.artist = get_multistring(vc, "ARTIST");
		
		// Album
		tags.album = get_multistring(vc, "ALBUM");

		// Disc Number
		tags.discnumber = get_string(vc, "DISCNUMBER");

		// Year
		tags.year = get_string(vc, "DATE");
		
		tags.tracknr = get_string(vc, "TRACKNUMBER");
		std::size_t sepat = tags.tracknr.find_first_of("/");
		if (sepat != std::string::npos)
		{
			tags.ntracks = tags.tracknr.substr(sepat + 1);
			tags.tracknr = tags.tracknr.substr(0, sepat);
		}

		// Genre
		tags.genre = get_multistring(vc, "GENRE");

		/*
		
	    // * Comment *
	    field_num = 0;
	    string1 = NULL; // Cause it may be not updated into the 'while' condition
	    while ( ((string2 = vorbis_comment_query(vc, (gchar*)"DESCRIPTION",field_num)) != NULL )   // New specifications
		 || ((string  = vorbis_comment_query(vc, (gchar*)"COMMENT",    field_num)) != NULL )   // Old : Winamp format (for EasyTAG 1.99.11 and older)
		 || ((string1 = vorbis_comment_query(vc, (gchar*)"",           field_num)) != NULL ) ) // Old : Xmms format   (for EasyTAG 1.99.11 and older)
	    {
		string  = Try_To_Validate_Utf8_String(string);
		string1 = Try_To_Validate_Utf8_String(string1);
		string2 = Try_To_Validate_Utf8_String(string2);

		if ( string2 && g_utf8_strlen(string2, -1) > 0 ) // Contains comment to new specifications format and we prefer this format (field name defined)
		{
		    if (FileTag->comment==NULL)
		        FileTag->comment = g_strdup(string2);
		    else
		        FileTag->comment = g_strconcat(FileTag->comment,MULTIFIELD_SEPARATOR,string2,NULL);

		    // Frees allocated data
		    if (string && g_utf8_strlen(string, -1) > 0)
		        g_free(string);
		    if (string1 && g_utf8_strlen(string1, -1) > 0)
		        g_free(string1);
		}else if ( string && g_utf8_strlen(string, -1) > 0 ) // Contains comment to Winamp format and we prefer this format (field name defined)
		{
		    if (FileTag->comment==NULL)
		        FileTag->comment = g_strdup(string);
		    else
		        FileTag->comment = g_strconcat(FileTag->comment,MULTIFIELD_SEPARATOR,string,NULL);

		    // Frees allocated data
		    if (string1 && g_utf8_strlen(string1, -1) > 0)
		        g_free(string1);
		}else if ( string1 && g_utf8_strlen(string1, -1) > 0 ) // Contains comment to Xmms format only
		{
		    if (FileTag->comment==NULL)
		        FileTag->comment = g_strdup(string1);
		    else
		        FileTag->comment = g_strconcat(FileTag->comment,MULTIFIELD_SEPARATOR,string1,NULL);
		}

		g_free(string);
		g_free(string1);
		g_free(string2);

		string  = NULL;
		string1 = NULL;
		field_num++;
	    }

	    // * Composer *
	    field_num = 0;
	    while ( (string = vorbis_comment_query(vc, (gchar*)"COMPOSER",field_num++)) != NULL )
	    {
		string = Try_To_Validate_Utf8_String(string);

		if ( g_utf8_strlen(string, -1) > 0 )
		{
		    if (FileTag->composer==NULL)
		        FileTag->composer = g_strdup(string);
		    else
		        FileTag->composer = g_strconcat(FileTag->composer,MULTIFIELD_SEPARATOR,string,NULL);
		}

		g_free(string);
	    }

	    // * Original artist *
	    field_num = 0;
	    while ( (string = vorbis_comment_query(vc, (gchar*)"PERFORMER",field_num++)) != NULL )
	    {
		string = Try_To_Validate_Utf8_String(string);

		if ( g_utf8_strlen(string, -1) > 0 )
		{
		    if (FileTag->orig_artist==NULL)
		        FileTag->orig_artist = g_strdup(string);
		    else
		        FileTag->orig_artist = g_strconcat(FileTag->orig_artist,MULTIFIELD_SEPARATOR,string,NULL);
		}

		g_free(string);
	    }

	    // * Copyright *
	    field_num = 0;
	    while ( (string = vorbis_comment_query(vc, (gchar*)"COPYRIGHT",field_num++)) != NULL )
	    {
		string = Try_To_Validate_Utf8_String(string);

		if ( g_utf8_strlen(string, -1) > 0 )
		{
		    if (FileTag->copyright==NULL)
		        FileTag->copyright = g_strdup(string);
		    else
		        FileTag->copyright = g_strconcat(FileTag->copyright,MULTIFIELD_SEPARATOR,string,NULL);
		}

		g_free(string);
	    }

	    // * URL *
	    field_num = 0;
	    while ( (string = vorbis_comment_query(vc, (gchar*)"LICENSE",field_num++)) != NULL )
	    {
		string = Try_To_Validate_Utf8_String(string);

		if ( g_utf8_strlen(string, -1) > 0 )
		{
		    if (FileTag->url==NULL)
		        FileTag->url = g_strdup(string);
		    else
		        FileTag->url = g_strconcat(FileTag->url,MULTIFIELD_SEPARATOR,string,NULL);
		}

		g_free(string);
	    }

	     // * Encoded by *
	    field_num = 0;
	    while ( (string = vorbis_comment_query(vc, (gchar*)"ENCODED-BY",field_num++)) != NULL )
	    {
		string = Try_To_Validate_Utf8_String(string);

		if ( g_utf8_strlen(string, -1) > 0 )
		{
		    if (FileTag->encoded_by==NULL)
		        FileTag->encoded_by = g_strdup(string);
		    else
		        FileTag->encoded_by = g_strconcat(FileTag->encoded_by,MULTIFIELD_SEPARATOR,string,NULL);
		}

		g_free(string);
	    }


	    // * Picture    *
	    // Non officials tags used for picture informations:
	    //  - COVERART            : contains the picture data
	    //  - COVERARTTYPE        : cover front, ...
	    //  - COVERARTDESCRIPTION : information set by user
	    //  - COVERARTMIME        : image/jpeg or image/png (written only)
	    //
	    field_num = 0;
	    while ( (string = vorbis_comment_query(vc, (gchar*)"COVERART",field_num++)) != NULL )
	    {
		gchar *data;
		gint size;
		Picture *pic;
		    
		pic = Picture_Allocate();
		if (!prev_pic)
		    FileTag->picture = pic;
		else
		    prev_pic->next = pic;
		prev_pic = pic;

		pic->data = NULL;
		
		// Decode picture data
		data = g_strdup(string);
		size = base64_decode(string, data);
		if ( data && (pic->data = (guchar*)g_memdup(data, size)) )
		    pic->size = size;
		g_free(data);

		if ( (string = vorbis_comment_query(vc, (gchar*)"COVERARTTYPE",field_num-1)) != NULL )
		{
		    pic->type = atoi(string);
		}

		if ( (string = vorbis_comment_query(vc, (gchar*)"COVERARTDESCRIPTION",field_num-1)) != NULL )
		{
		    pic->description = g_strdup(string);
		}

		//if ((string = vorbis_comment_query(vc, (gchar*)"COVERTARTMIME",field_num-1)) != NULL )
		//{
		//    pic->description = g_strdup(string);
		//}

	    }


	    // * Save unsupported fields *
	    for (i=0;i<(guint)vc->comments;i++)
	    {
		if ( strncasecmp(vc->user_comments[i],"TITLE=",            6) != 0
		  && strncasecmp(vc->user_comments[i],"ARTIST=",           7) != 0
		  && strncasecmp(vc->user_comments[i],"ALBUM=",            6) != 0
		  && strncasecmp(vc->user_comments[i],"DISCNUMBER=",      11) != 0
		  && strncasecmp(vc->user_comments[i],"DATE=",             5) != 0
		  && strncasecmp(vc->user_comments[i],"TRACKNUMBER=",     12) != 0
		  && strncasecmp(vc->user_comments[i],"TRACKTOTAL=",      11) != 0
		  && strncasecmp(vc->user_comments[i],"GENRE=",            6) != 0
		  && strncasecmp(vc->user_comments[i],"DESCRIPTION=",     12) != 0
		  && strncasecmp(vc->user_comments[i],"COMMENT=",          8) != 0
		  && strncasecmp(vc->user_comments[i],"=",                 1) != 0
		  && strncasecmp(vc->user_comments[i],"COMPOSER=",         9) != 0
		  && strncasecmp(vc->user_comments[i],"PERFORMER=",       10) != 0
		  && strncasecmp(vc->user_comments[i],"COPYRIGHT=",       10) != 0
		  && strncasecmp(vc->user_comments[i],"LICENSE=",          8) != 0
		  && strncasecmp(vc->user_comments[i],"ENCODED-BY=",      11) != 0
		  && strncasecmp(vc->user_comments[i],"COVERART=",         9) != 0
		  && strncasecmp(vc->user_comments[i],"COVERARTTYPE=",       13) != 0
		  && strncasecmp(vc->user_comments[i],"COVERARTMIME=",       13) != 0
		  && strncasecmp(vc->user_comments[i],"COVERARTDESCRIPTION=",20) != 0
		   )
		{
		    FileTag->other = g_list_append(FileTag->other,
		                                   Try_To_Validate_Utf8_String(vc->user_comments[i]));
		}
	    }
	    */

	    vcedit_clear(state);
	    fclose(file);
	    //g_free(filename_utf8);

	    return READVAL_OK;
	}

}





